/***********************************************************************
 * Copyright (c)  2008 - 2021, dxtc Co.,Ltd .
 * All rights reserved.
 * Filename    : owh_app.c
 * Description : owh application demo
 * Author(s)   : liujia
 * version     : V1.0
 * Modify date : 2023-02-14
 ***********************************************************************/
#include "device.h"
#include "component.h"
#include "bat_encrypt.h"

#define BAT_ENCRYPT_END   	10
#define BAT_ENCRYPT_ERROR 	11 

typedef uint8_t (*bat_get_memory_page_fnct)    		(uint32_t num_index,uint8_t *data);
typedef uint8_t (*bat_set_memory_page_fnct)    		(uint32_t num_index,uint8_t *data);
typedef uint8_t (*bat_write_count_value_fnct)  		(void);
typedef uint8_t (*bat_read_count_value_fnct)   		(uint32_t *counter_value);
typedef uint8_t (*bat_processor_fnct)     			(void);
typedef uint8_t (*bat_init_fnct)     				(void);
typedef void (*bat_deinit_fnct)     				(void);

struct bat_task_cbs
{
	bat_get_memory_page_fnct get_memory_page;
	bat_set_memory_page_fnct set_memory_page;
	bat_write_count_value_fnct write_count_value;
	bat_read_count_value_fnct read_count_value;
	bat_processor_fnct bat_processor;
	bat_init_fnct bat_init;
	bat_deinit_fnct bat_deinit;
	uint8_t count_addr;
	uint8_t precent_addr;
};

#include "owh.h"
#include "sle95.h"

static uint8_t bat_index = 0;//电池加密的id 0:表示英飞凌，1：表示航芯
struct bat_task_cbs bat_cbs_table[2]={{Cmd_Yfl_Get_Memory_Page,Cmd_Yfl_Set_Memory_Page,Hal_Yfl_Write_Counter_Value,Hal_Yfl_Read_Counter_Value,Sle95_Processor,auths_init,auths_deinit,8,0},\
									  {Cmd_Owh_Get_Memory_Page,Cmd_Owh_Set_Memory_Page,Hal_Owh_Write_Counter_Value,Hal_Owh_Read_Counter_Value,Acl16_Processor,Hal_Owh_IIC_Init,Hal_Owh_IIC_Deinit,3,2}};

uint8_t bat_count_addr,bat_percent_addr;
#define EVENT_READ_ENCRYPT (0X00000001)
#define EVENT_READ_COUNT (0X00000002)
// #define POWER_AUDO_REPORTED  1		//自动发送电量消息，用于测试
#ifdef POWER_AUDO_REPORTED
#define EVENT_UPDATE_ADC (0X00000004)
#endif
static uint8_t first_power_flag = 0;
static uint8_t status_commun = 0;		//0：通讯失败，1：通讯成功
#define VHW_PIN_Encrypt_Power		vPIN_C6

void Bat_printf_buff_byte(const uint8_t* buff, uint32_t length)
{
	uint32_t i;

	for(i=0;i<length;i++)
	{
		printf("%02X", buff[i]);	
	}
	printf("\r\n");
}

/**
 * @brief  处理邮箱发来的数据
 * @return
 */
static void Bat_Encry_ProcessMbox(void *msg)
{
	uint16_t bRet;
	uint16_t temp_msg,temp_data;//当前电量,记录的电量
	uint8_t temp_record[32]={0};
	Bat_Encrypt_Msg_t *temp = (Bat_Encrypt_Msg_t *)msg;
	Bat_Encrypt_Msg_t ack_msg;
	uint32_t dcvalue = 0;

	if(status_commun == 0)		//通讯失败不进行下面的流程
	{
		printf("bat encrty commun is fail\r\n");
		memset(&ack_msg,0,sizeof(Bat_Encrypt_Msg_t));
		ack_msg.status = 1;//代表失败
		OSAL_MessagePublish(&ack_msg, sizeof(Bat_Encrypt_Msg_t));
		return ;
	}
	temp_msg = temp->percentage;
	//获取储存的电池电量
	bat_cbs_table[bat_index].get_memory_page(bat_percent_addr,temp_record);
	temp_data = temp_record[0]+(temp_record[1]<<8);
	printf("before:%d,now:%d\r\n",temp_data,temp_msg);

	if((temp_msg < 0)||(temp_msg > 100))
	{
		printf("bat is out of 0-100\r\n");
		return ;
	}

	if((temp_data < 0)||(temp_data > 100))
	{
		printf("record bat is out of 0-100,set 100 as original\r\n");
		temp_data = 100;
	}

	if(temp_msg < temp_data)
	{
		if((temp_data-temp_msg) > 10)		//电量下降超过10%，更新电量记录值
		{
			printf("power is down 10 percentage\r\n");
			memset(temp_record,0,32);
			temp_record[0] = temp_msg%256;
			temp_record[1] = temp_msg/256;
			bRet = bat_cbs_table[bat_index].set_memory_page(bat_percent_addr,temp_record);
			if(bRet)
			{
				printf("bat_percent_addr Set_Memory_Page Fail:%d.\r\n",bRet);
				return;
			}
		}
	}
	else
	{
		if((temp_msg - temp_data) > 30)	//电量回升30%以上认为是充过电了
		{
			printf("power is up 30 percentage\r\n");
			//计数减1
			bRet = bat_cbs_table[bat_index].write_count_value();
			if(bRet)
			{
				printf("Write_Counter_Value Test Fail.\r\n");
				return;
			}
			//打印当前计数值
			bRet = bat_cbs_table[bat_index].read_count_value(&dcvalue);
			if(bRet)
			{
				printf("Read_Counter_Value Test Fail.\r\n");
				return;
			}
			printf("DC_CNT:  %d.\r\n",dcvalue);
			
			//更新当前电量值
			memset(temp_record,0,32);
			temp_record[0] = temp_msg%256;
			temp_record[1] = temp_msg/256;
			bRet = bat_cbs_table[bat_index].set_memory_page(bat_percent_addr,temp_record);
			if(bRet)
			{
				printf("bat_percent_addr Set_Memory_Page Fail:%d.\r\n",bRet);
				return;
			}

		}
	}

}
/**
  * @brief  Battery任务函数
  *
  * @note   1.任务函数内不能写阻塞代码
  *         2.任务函数每次运行只处理一个事件
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Bat_Encrypt_Task(uint32_t event)
{
	Bat_Encrypt_Msg_t msg;
	uint32_t ret;
	uint8_t bRet,bRet1,bRet2;
	#ifdef POWER_AUDO_REPORTED
	static uint8_t adc_value = 100;
	static Bat_Encrypt_Msg_t test_msg;
	#endif
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		uint8_t i;
		printf("Bat_Encrypt_Task\r\n");
		Device_Write(VHW_PIN_Encrypt_Power, 0, 0, 1);

		for( i=0;i<2;i++)		//自动识别一下驱动
		{
			if(bat_cbs_table[i].bat_init() == 0)
			{
				bat_index = i;
				printf("bat_index:%d\r\n",bat_index);
				break;
			}
		}
		printf("i:%d\r\n",i);
		if(i != 2)
		{
			if((first_power_flag == 0)||(status_commun == 0))//第一次上电，或者之前初始化不成功，唤醒后重新初始化一遍
			{
				first_power_flag = 1;
				OSAL_EventRepeatCreate(COMP_BATTERY_ENCRY, EVENT_READ_ENCRYPT, 50, EVT_PRIORITY_LOW);
			}

			printf("final bat_index:%d\r\n",bat_index);
			bat_count_addr = bat_cbs_table[bat_index].count_addr;
			bat_percent_addr = bat_cbs_table[bat_index].precent_addr;
			
			OSAL_EventSingleCreate(COMP_BATTERY_ENCRY, EVENT_READ_COUNT, 2000, EVT_PRIORITY_LOW);

			#ifdef POWER_AUDO_REPORTED
			OSAL_EventRepeatCreate(COMP_BATTERY_ENCRY, EVENT_UPDATE_ADC, 1000, EVT_PRIORITY_LOW);
			#endif
		}
		// APP_OWH_Check();
		// sample_demo();
		return ( event ^ EVENT_SYS_START );
	}
	#ifdef POWER_AUDO_REPORTED
	/* 自动上报递减电量用于测试 */
	if (event & EVENT_UPDATE_ADC)
	{
		printf("adc_value : %d\r\n",adc_value--);
		if(adc_value == 0)
		{
			adc_value = 100;
		}
		test_msg.percentage = adc_value;
		Bat_Encry_ProcessMbox(&test_msg);
		return ( event ^ EVENT_UPDATE_ADC );
    }
	#endif
	/* 加密验证事件 */
	if (event & EVENT_READ_ENCRYPT)
	{
		ret = bat_cbs_table[bat_index].bat_processor();
		if((ret == BAT_ENCRYPT_ERROR)||(ret == BAT_ENCRYPT_END))
		{
			printf("ret:%d\r\n",ret);
			OSAL_EventDelete(COMP_BATTERY_ENCRY,EVENT_READ_ENCRYPT);
			if(ret == BAT_ENCRYPT_END)	//通信成功标记状态
			{
				status_commun = 1;
			}
			else
			{
				status_commun = 0;
			}
		}
		return ( event ^ EVENT_READ_ENCRYPT );
    }

	/* 读取count次数 */
	if (event & EVENT_READ_COUNT)
	{
		uint8_t read_data[32] = {0};
		char message[32]="dxtc";
		uint8_t temp_record[32];
		uint32_t count,count_original;//当前值，原始写入的值
		if(status_commun == 1)	//与加密芯片通信完成，并成功的标志
		{
			bRet1 = bat_cbs_table[bat_index].read_count_value(&count);//0xc0
			if(bRet1)
			{
				printf("Read_Counter_Value Test Fail.\r\n");
			}		

			bRet2 = bat_cbs_table[bat_index].get_memory_page(bat_count_addr,read_data);
			if(bRet2)
			{
				printf("Get_Memory_Page Test Fail.\r\n");
			}
			else
			{
				printf("read_data:");
				Bat_printf_buff_byte(read_data,32);
				printf("\r\n");
			}

			if(bRet1||bRet2)
			{
				printf("get data fail\r\n");
			}
			else
			{
				//对比是否未写入次数
				if (memcmp(read_data, message, 6) == 0)	//已经写入后上报差值
				{
					//换算保存的初值
					count_original = read_data[9];
					count_original = read_data[8]+(count_original<<8);
					count_original = read_data[7]+(count_original<<8);
					count_original = read_data[6]+(count_original<<8);

					memset(&msg,0,sizeof(Bat_Encrypt_Msg_t));
					msg.count = count_original  - count;//计算差值
					printf("publish msg ,count:%u\r\n",msg.count);
					OSAL_MessagePublish(&msg, sizeof(Bat_Encrypt_Msg_t));
				}
				else			//未写入次数后，重新写入count初值及电量初值
				{
					message[6] = count%256;
					message[7] = (count>>8)%256;
					message[8] = (count>>16)%256;
					message[9] = count>>24;
					bRet = bat_cbs_table[bat_index].set_memory_page(bat_count_addr,message);
					if(bRet)
					{
						printf("write count_original fail\r\n");
					}
					else
					{
						printf("write count_original success\r\n");
					}
					
					memset(temp_record,0,32);
					temp_record[0] = 100;
					bRet = bat_cbs_table[bat_index].set_memory_page(bat_percent_addr,temp_record);
					if(bRet)
					{
						printf("bat_percent_addr Set_Memory_Page Fail:%d.\r\n",bRet);
					}
				}
			}
		}	
		else
		{
			printf("bat encrypt is fail\r\n");
		}

		return ( event ^ EVENT_READ_COUNT );
    }

	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
		bat_cbs_table[bat_index].bat_deinit();
		Device_Write(VHW_PIN_Encrypt_Power, 0, 0, 0);
		#ifdef POWER_AUDO_REPORTED
		OSAL_EventDelete(COMP_BATTERY_ENCRY,EVENT_UPDATE_ADC);
		#endif
		return ( event ^ EVENT_SYS_SLEEP );
    }
	
	/* 系统邮箱事件 */
    if (event & EVENT_SYS_MBOX)
    {
        uint8_t buffer[30] = {0};
        if (OSAL_MboxAccept(buffer))
        {
            Bat_Encry_ProcessMbox(buffer);
            OSAL_EventSingleCreate(COMP_BATTERY_ENCRY, EVENT_SYS_MBOX, 20, EVT_PRIORITY_MEDIUM);
        }
        return (event ^ EVENT_SYS_MBOX);
    }
	
	return 0;
}
COMPONENT_TASK_EXPORT(COMP_BATTERY_ENCRY, Bat_Encrypt_Task, 0);